/*
 * jQuery Idle Timeout 1.2
 * Copyright (c) 2011 Eric Hynds
 *
 * http://www.erichynds.com/jquery/a-new-and-improved-jquery-idle-timeout-plugin/
 *
 * Depends:
 *  - jQuery 1.4.2+
 *  - jQuery Idle Timer (by Paul Irish, http://paulirish.com/2009/jquery-idletimer-plugin/)
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
*/

(function($, win){
    
    var idleTimeout = {
        init: function(element, resume, options){
            var self = this, elem;

            this.warning = elem = $(element);
            this.resume = $(resume);
            this.options = options;
            this.countdownOpen = false;
            this.failedRequests = options.failedRequests;
            this._startTimer();
            this.title = document.title;
            
            // expose obj to data cache so peeps can call internal methods
            $.data( elem[0], "idletimeout", this );
            
            // start the idle timer
            $.idleTimer(options.idleAfter * 1000);
            
            // once the user becomes idle
            $(document).bind("idle.idleTimer", function(){
                
                // if the user is idle and a countdown isn't already running
                if( $.data(document, "idleTimer") === "idle" && !self.countdownOpen ){
                    self._stopTimer();
                    self.countdownOpen = true;
                    self._idle();
                }
            });
            
            // bind continue link
            this.resume.bind("click", function(e){
                e.preventDefault();
                
                win.clearInterval(self.countdown);   // stop the countdown
                self.countdownOpen = false;          // stop countdown
                self._startTimer();                  // start up the timer again
                self._keepAlive(false);              // ping server
                options.onResume.call(self.warning); // call the resume callback
            });
        },
        
        _idle: function() {
            var self = this,
                options = this.options,
                warning = this.warning[0],
                counter = options.warningLength;
                
            // fire the onIdle function
            options.onIdle.call(warning);
            
            // set inital value in the countdown placeholder
            options.onCountdown.call(warning, counter);
            
            // create a timer that runs every second
            this.countdown = win.setInterval(function() {
                if(--counter === 0){
                    window.clearInterval(self.countdown);
                    options.onTimeout.call(warning);
                } else {
                    options.onCountdown.call(warning, counter);
                    document.title = options.titleMessage.replace("%s", counter) + self.title;
                }
            }, 1000);
        },
        
        _startTimer: function() {
            var self = this;

            this.timer = win.setTimeout(function(){
                self._keepAlive();
            }, this.options.pollingInterval * 1000);
        },
        
        _stopTimer: function() {
            // reset the failed requests counter
            this.failedRequests = this.options.failedRequests;
            win.clearTimeout(this.timer);
        },
        
        _keepAlive: function( recurse ){
            var self = this,
                options = this.options;
                
            //Reset the title to what it was.
            document.title = self.title;
            
            // assume a startTimer/keepAlive loop unless told otherwise
            if (typeof recurse === "undefined"){
                recurse = true;
            }
            
            // if too many requests failed, abort
            if (!this.failedRequests) {
                this._stopTimer();
                options.onAbort.call( this.warning[0] );
                return;
            }

            if(options.keepAliveURL != null && options.keepAliveURL.length > 0) {
            
                $.ajax({
                    timeout: options.AJAXTimeout,
                    url: options.keepAliveURL,
                    error: function() {
                        self.failedRequests--;
                    },
                    success: function(response) {
                        if($.trim(response) !== options.serverResponseEquals) {
                            self.failedRequests--;
                        }
                    },
                    complete: function() {
                        if(recurse){
                            self._startTimer();
                        }
                    }
                });

            } else {
                if (recurse) {
                    self._startTimer();
                }
            }
        }
    };
    
    // expose
    $.idleTimeout = function(element, resume, options){
        idleTimeout.init( element, resume, $.extend($.idleTimeout.options, options) );
        return this;
    };
    
    // options
    $.idleTimeout.options = {
        // number of seconds after user is idle to show the warning
        warningLength: 30,
        
        // url to call to keep the session alive while the user is active
        keepAliveURL: "",
        
        // the response from keepAliveURL must equal this text:
        serverResponseEquals: "OK",
        
        // user is considered idle after this many seconds.  10 minutes default
        idleAfter: 600,
        
        // a polling request will be sent to the server every X seconds
        pollingInterval: 60,
        
        // number of failed polling requests until we abort this script
        failedRequests: 5,
        
        // the $.ajax timeout in MILLISECONDS!
        AJAXTimeout: 250,
        
        // %s will be replaced by the counter value
        titleMessage: "Warning: %s seconds until log out | ",
        
        /*
        Callbacks
        "this" refers to the element found by the first selector passed to $.idleTimeout.
        */
        // callback to fire when the session times out
        onTimeout: $.noop,
        
        // fires when the user becomes idle
        onIdle: $.noop,
        
        // fires during each second of warningLength
        onCountdown: $.noop,
        
        // fires when the user resumes the session
        onResume: $.noop,
        
        // callback to fire when the script is aborted due to too many failed requests
        onAbort: $.noop
    };
    
})(jQuery, window);

